Sensor Fusion for Kinetis MCUs (ISSDK/KSDK version)
driver_FXLS8952.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016, NXP Semiconductor
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without modification,
6  * are permitted provided that the following conditions are met:
7  *
8  * o Redistributions of source code must retain the above copyright notice, this list
9  * of conditions and the following disclaimer.
10  *
11  * o Redistributions in binary form must reproduce the above copyright notice, this
12  * list of conditions and the following disclaimer in the documentation and/or
13  * other materials provided with the distribution.
14  *
15  * o Neither the name of Freescale Semiconductor, Inc. nor the names of its
16  * contributors may be used to endorse or promote products derived from this
17  * software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
23  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 /*! \file driver_FXLS8952.c
31  \brief Provides init() and read() functions for the FXLS8952 3-axis accelerometer
32 */
33 
34 #include "board.h" // generated by Kinetis Expert. Long term - merge sensor_board.h into this file
35 #include "sensor_fusion.h" // Sensor fusion structures and types
36 #include "sensor_io_i2c.h" // Required for registerreadlist_t / registerwritelist_t declarations
37 #include "sensor_drv.h" // Contains sensor state and error definitions
38 #include "FXLS8952.h" // describes the FXLS8952 register definition and its bit mask
39 #include "drivers.h" // Device specific drivers supplied by NXP (can be replaced with user drivers)
40 #define FXLS8952_COUNTSPERG 512
41 #define FXLS8952_ACCEL_FIFO_SIZE 32
42 
43 #if F_USING_ACCEL
44 
45 // Command definition to read the WHO_AM_I value.
46 const registerreadlist_t FXLS8952_WHO_AM_I_READ[] =
47 {
48  { .readFrom = FXLS8952_WHO_AM_I, .numBytes = 1 }, __END_READ_DATA__
49 };
50 
51 // Command definition to read the number of entries in the accel FIFO.
52 const registerreadlist_t FXLS8952_BUF_STATUS_READ[] =
53 {
54  { .readFrom = FXLS8952_BUF_STATUS, .numBytes = 1 }, __END_READ_DATA__
55 };
56 
57 // Command definition to read the number of entries in the accel FIFO.
58 registerreadlist_t FXLS8952_DATA_READ[] =
59 {
60  { .readFrom = FXLS8952_BUF_X_LSB, .numBytes = 6 }, __END_READ_DATA__
61 };
62 
63 // Each entry in a RegisterWriteList is composed of: register address, value to write, bit-mask to apply to write (0 enables)
64 const registerwritelist_t FXLS8952_Initialization[] =
65 {
66  // write 0000 0000 = 0x00 to SENS_CONFIG1 to place FXLS8952 into standby
67  // [7-1]: Set when taking the part out of standby
68  // [0]: ACTIVE=0 for standby
69  { FXLS8952_SENS_CONFIG1, 0x00, 0x00 },
70 
71  // write 0010 0000 = 0x20 to BUF_CONFIG1 to enable FIFO in continuous (circular) mode
72  // [7]: BUF_TYPE=0 for FIFO (not FILO) operation
73  // [6-5]: BUF_MODE[1-0]=01 for FIFO continuous mode
74  // [4]: BUF_GATE=0 to flush buffer on transitions
75  // [3]: TRIG_SDCD_AND=0
76  // [2]: TRIG_SDCD_OR=0
77  // [1] Reserved=0
78  // [0]: TRIG_ORIENT=0
79  { FXLS8952_BUF_CONFIG1, 0x20, 0x00 },
80 
81  // write 0101 0000 = 0x50 to SENS_CONFIG2 register to set High Performance Mode
82  // [7-6]: WAKE_PM=01 for High Performance Mode
83  // [5-4]: SLEEP_PM=01 for High Performance Mode
84  // [3]: LE_BE=0 for Little Endian
85  // [2]: BLOCK=0 for normal latching
86  // [1]: AINC_TEMP=0 to not include temperature in auto increment
87  // [0]: F_READ=0 for normal 12 bit reads
88  { FXLS8952_SENS_CONFIG2, 0x50, 0x00 },
89 
90  // write XXXX 0000 = to SENS_CONFIG3 register to set ODR
91  // [7-4]: WAKE_ODR=1100 for 0.781Hz ODR and 4096x decimation from 3200Hz giving 0xC0
92  // [7-4]: WAKE_ODR=1011 for 1.56Hz ODR and 12048x decimation from 3200Hz giving 0xB0
93  // [7-4]: WAKE_ODR=1010 for 3.125Hz ODR and 1024x decimation from 3200Hz giving 0xA0
94  // [7-4]: WAKE_ODR=1001 for 6.25Hz ODR and 512x decimation from 3200Hz giving 0x90
95  // [7-4]: WAKE_ODR=1000 for 12.5Hz ODR and 256x decimation from 3200Hz giving 0x80
96  // [7-4]: WAKE_ODR=0111 for 25Hz ODR and 128x decimation from 3200Hz giving 0x70
97  // [7-4]: WAKE_ODR=0110 for 50Hz ODR and 64x decimation from 3200Hz giving 0x60
98  // [7-4]: WAKE_ODR=0101 for 100Hz ODR and 32x decimation from 3200Hz giving 0x50
99  // [7-4]: WAKE_ODR=0100 for 200Hz ODR and 16x decimation from 3200Hz giving 0x40
100  // [7-4]: WAKE_ODR=0011 for 400Hz ODR and 8x decimation from 3200Hz giving 0x30
101  // [7-4]: WAKE_ODR=0010 for 800Hz ODR and 4x decimation from 3200Hz giving 0x20
102  // [7-4]: WAKE_ODR=0001 for 1600Hz ODR and 2x decimation from 3200Hz giving 0x10
103  // [7-4]: WAKE_ODR=0000 for 3200Hz ODR and 1x decimation from 3200Hz giving 0x00
104  // [3-0]: SLEEP_ODR=0000
105 #if (ACCEL_ODR_HZ <= 1) // select 0.781Hz ODR
106  { FXLS8952_SENS_CONFIG3, 0xC0, 0x00 },
107 #elif (ACCEL_ODR_HZ <= 2) // select 1.5625Hz ODR
108  { FXLS8952_SENS_CONFIG3, 0x80, 0x00 },
109 #elif (ACCEL_ODR_HZ <= 3) // select 3.125Hz ODR
110  { FXLS8952_SENS_CONFIG3, 0xA0, 0x00 },
111 #elif (ACCEL_ODR_HZ <= 6) // select 6.25Hz ODR
112  { FXLS8952_SENS_CONFIG3, 0x90, 0x00 },
113 #elif (ACCEL_ODR_HZ <= 12) // select 12.5Hz ODR
114  { FXLS8952_SENS_CONFIG3, 0x80, 0x00 },
115 #elif (ACCEL_ODR_HZ <= 25) // select 25Hz ODR
116  { FXLS8952_SENS_CONFIG3, 0x70, 0x00 },
117 #elif (ACCEL_ODR_HZ <= 50) // select 50Hz ODR
118  { FXLS8952_SENS_CONFIG3, 0x60, 0x00 },
119 #elif (ACCEL_ODR_HZ <= 100) // select 100Hz ODR
120  { FXLS8952_SENS_CONFIG3, 0x50, 0x00 },
121 #elif (ACCEL_ODR_HZ <= 200) // select 200Hz ODR
122  { FXLS8952_SENS_CONFIG3, 0x40, 0x00 },
123 #elif (ACCEL_ODR_HZ <= 400) // select 400Hz ODR
124  { FXLS8952_SENS_CONFIG3, 0x30, 0x00 },
125 #elif (ACCEL_ODR_HZ <= 800) // select 800Hz ODR
126  { FXLS8952_SENS_CONFIG3, 0x20, 0x00 },
127 #elif (ACCEL_ODR_HZ <= 1600) // select 1600Hz ODR
128  { FXLS8952_SENS_CONFIG3, 0x10, 0x00 },
129 #else // select 3200Hz ODR
130  { FXLS8952_SENS_CONFIG3, 0x00, 0x00 },
131 #endif
132 
133  // write 0000 0011 = 0x03 to SENS_CONFIG1 to configure 4g mode and Active mode
134  // [7]: RST=0 for no software reset
135  // [6-5]: ST_AXIS_SEL=00 to disable self test
136  // [4]: ST_POL=0 (default)
137  // [3]: AWS_EN=0 (default)
138  // [2-1]: FSR=01 for 4g mode
139  // [1]: ACTIVE=1 for standby
140  { FXLS8952_SENS_CONFIG1, 0x03, 0x00 },
141  __END_WRITE_DATA__
142 };
143 
144 // All sensor drivers and initialization functions have the same prototype.
145 // sfg is a pointer to the master "global" sensor fusion structure.
146 // sensor = pointer to linked list element used by the sensor fusion subsystem to specify required sensors
147 
148 // sfg = pointer to top level (generally global) data structure for sensor fusion
150 {
151  int32_t status;
152  uint8_t reg;
153  status = Register_I2C_Read(sensor->bus_driver, sensor->addr, FXLS8952_WHO_AM_I, 1, &reg);
154  if (status==SENSOR_ERROR_NONE) {
155  if (reg==FXLS8952_WHOAMI_VALUE) {
156  sfg->Accel.iWhoAmI = reg;
157  } else {
158  return(SENSOR_ERROR_INIT);
159  }
160  } else {
161  return(status);
162  }
163 
164  // Configure and start the FXLS8952 sensor. This does multiple register writes
165  // (see FXLS8952_Initialization definition above)
166  status = Sensor_I2C_Write(sensor->bus_driver, sensor->addr, FXLS8952_Initialization );
167 
168  // Stash some needed constants in the SF data structure for this sensor
169  sfg->Accel.iCountsPerg = FXLS8952_COUNTSPERG;
170  sfg->Accel.fgPerCount = 1.0F / FXLS8952_COUNTSPERG;
171  sfg->Accel.fgPerCount = 1.0F / FXLS8952_COUNTSPERG;
172 
173  sensor->isInitialized = F_USING_ACCEL;
174  sfg->Accel.isEnabled = true;
175 
176  return (status);
177 }
178 
180 {
181  uint8_t I2C_Buffer[6 * FXLS8952_ACCEL_FIFO_SIZE]; // I2C read buffer
182  int8_t status; // I2C transaction status
183  int8_t j; // scratch
184  uint8_t sensor_fifo_count = 1;
185  int16_t sample[3];
186 
187  if(sensor->isInitialized != F_USING_ACCEL)
188  {
189  return SENSOR_ERROR_INIT;
190  }
191 
192  // read the XLS8952_BUF_STATUS register (mapped to STATUS) and extract number of measurements available (lower 6 bits)
193  status = Sensor_I2C_Read(sensor->bus_driver, sensor->addr, FXLS8952_BUF_STATUS_READ, I2C_Buffer );
194  if (status==SENSOR_ERROR_NONE) {
195  sensor_fifo_count = I2C_Buffer[0] & 0x3F;
196  // return if there are no measurements in the sensor FIFO.
197  // this will only occur when the FAST_LOOP_HZ equals or exceeds ACCEL_ODR_HZ
198  if (sensor_fifo_count == 0) return status;
199  } else {
200  return(status);
201  }
202 
203  FXLS8952_DATA_READ[0].numBytes = 6 * sensor_fifo_count;
204  status = Sensor_I2C_Read(sensor->bus_driver, sensor->addr, FXLS8952_DATA_READ, I2C_Buffer );
205 
206  if (status==SENSOR_ERROR_NONE) {
207  // process the pthisAccel->iFIFOCount * three channels of data
208  for (j = 0; j < sensor_fifo_count; j++)
209  {
210  // place the 6 bytes read into the 16 bit accelerometer structure
211  sample[CHX] = (I2C_Buffer[6 * j + 1] << 8) | I2C_Buffer[6 * j + 0];
212  sample[CHY] = (I2C_Buffer[6 * j + 3] << 8) | I2C_Buffer[6 * j + 2];
213  sample[CHZ] = (I2C_Buffer[6 * j + 5] << 8) | I2C_Buffer[6 * j + 4];
214  conditionSample(sample); // truncate negative values to -32767
215  addToFifo((FifoSensor*) &(sfg->Accel), ACCEL_FIFO_SIZE, sample);
216  }
217  }
218 
219  return (status);
220 }
221 
222 
223 // Each entry in a RegisterWriteList is composed of: register address, value to write, bit-mask to apply to write (0 enables)
224 const registerwritelist_t FXLS8952_IDLE[] =
225 {
226  // Set ACTIVE = other bits unchanged
227  { FXLS8952_SENS_CONFIG1, 0x00, 0x01 },
228  __END_WRITE_DATA__
229 };
230 
231 // FXLS8952_Idle places the sensor into Standby mode (see datasheet for wakeup time)
233 {
234  int32_t status;
235  if(sensor->isInitialized == F_USING_ACCEL) {
236  status = Sensor_I2C_Write(sensor->bus_driver, sensor->addr, FXLS8952_IDLE );
237  sensor->isInitialized = 0;
238  sfg->Accel.isEnabled = false;
239  } else {
240  return SENSOR_ERROR_INIT;
241  }
242  return status;
243 }
244 #endif // if F_USING_ACCEL
int8_t FXLS8952_Read(PhysicalSensor *sensor, SensorFusionGlobals *sfg)
#define CHY
Used to access Y-channel entries in various data data structures.
Definition: sensor_fusion.h:77
void addToFifo(FifoSensor *sensor, uint16_t maxFifoSize, int16_t sample[3])
addToFifo is called from within sensor driver read functions
The top level fusion structure.
void * bus_driver
should be of type (ARM_DRIVER_I2C* for I2C-based sensors, ARM_DRIVER_SPI* for SPI) ...
#define ACCEL_FIFO_SIZE
FXOS8700 (accel), MMA8652, FXLS8952 all have 32 element FIFO.
The FifoSensor union allows us to use common pointers for Accel, Mag & Gyro logical sensor structures...
The sensor_fusion.h file implements the top level programming interface.
#define FXLS8952_COUNTSPERG
#define CHZ
Provides function prototypes for driver level interfaces.
int8_t FXLS8952_Idle(PhysicalSensor *sensor, SensorFusionGlobals *sfg)
#define FXLS8952_ACCEL_FIFO_SIZE
#define CHX
Used to access X-channel entries in various data data structures.
Definition: sensor_fusion.h:76
int8_t FXLS8952_Init(PhysicalSensor *sensor, SensorFusionGlobals *sfg)
void conditionSample(int16_t sample[3])
conditionSample ensures that we never encounter the maximum negative two&#39;s complement value for a 16-...
An instance of PhysicalSensor structure type should be allocated for each physical sensors (combo dev...
uint16_t isInitialized
Bitfields to indicate sensor is active (use SensorBitFields from build.h)
#define F_USING_ACCEL
nominally 0x0001 if an accelerometer is to be used, 0x0000 otherwise
SensorFusionGlobals sfg
This is the primary sensor fusion data structure.
uint16_t addr
I2C address if applicable.